import { isStrOrNum, isArray } from '../shared/utils';
import createFiber from '../reconciler/ReactFiber';
import {
  sameNode,
  deleteRemainingChildren,
  mapRemainingChildren,
  deleteChild,
} from './ReactChildFiberAssistant';
import { Placement, Update } from '../shared/utils';

export function reconcileChildren(returnFiber, children) {
  if (isStrOrNum(children)) return;
  let newChildren;
  if (!children) {
    newChildren = [];
  } else {
    newChildren = isArray(children) ? children : [children];
  }

  let previousNewFiber = null;
  let i = 0;
  let oldFiber = returnFiber.alternate?.child;
  let shouldTrackEffects = !!returnFiber.alternate;
  let lastPlacedIndex = 0; // 上一次 DOM 节点插入的最远位置

  // 该变量有两个作用：
  // 1. 存储下一个旧的 fiber 对象
  // 2. 临时存储当前的旧的 fiber 对象
  let nextOldFiber = null;

  for (; oldFiber && i < newChildren.length; i++) {
    // console.log(newChildren[i], 'log');
    const newChildVnode = newChildren[i];
    if (newChildVnode === null) continue; // 可能 是 null 这种情况
    if (oldFiber.index > i) {
      nextOldFiber = oldFiber;
      oldFiber = null;
    } else {
      nextOldFiber = oldFiber.sibling;
    }
    const isSame = sameNode(newChildVnode, oldFiber);
    if (!isSame) {
      oldFiber = nextOldFiber;
      break;
    }

    const newFiber = createFiber(newChildVnode, returnFiber);
    Object.assign(newFiber, {
      stateNode: oldFiber.stateNode,
      alternate: oldFiber,
      flags: Update, // 同一设置为更新
    });

    lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, i, shouldTrackEffects);

    if (!previousNewFiber) {
      returnFiber.child = newFiber;
    } else {
      previousNewFiber.sibling = newFiber;
    }
    previousNewFiber = newFiber;
    oldFiber = nextOldFiber;
  }
  if (i === newChildren.length) {
    deleteRemainingChildren(returnFiber, oldFiber);
    return;
  }

  if (!oldFiber) {
    for (; i < newChildren.length; i++) {
      const newChildVnode = newChildren[i];
      const newFiber = createFiber(newChildVnode, returnFiber);
      lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, i, shouldTrackEffects);
      if (!previousNewFiber) {
        returnFiber.child = newFiber;
      } else {
        previousNewFiber.sibling = newFiber;
      }
      previousNewFiber = newFiber;
    }
  }

  const existingChildren = mapRemainingChildren(oldFiber);

  for (; i < newChildren.length; i++) {
    const newChildVnode = newChildren[i];

    if (newChildVnode === null) continue;
    const newFiber = createFiber(newChildVnode, returnFiber);
    const matchedFiber = existingChildren.get(newFiber.key || newFiber.index);
    if (matchedFiber) {
      Object.assign(newFiber, {
        stateNode: matchedFiber.stateNode,
        alternate: matchedFiber,
        flags: Update, // 同一设置为更新
      });
      existingChildren.delete(newFiber.key || newFiber.index);
    }

    // 更新 lastPlacedIndex 的值
    lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, i, shouldTrackEffects);
    if (!previousNewFiber) {
      returnFiber.child = newFiber;
    } else {
      previousNewFiber.sibling = newFiber;
    }
    previousNewFiber = newFiber;
  }

  if (shouldTrackEffects) {
    existingChildren.forEach((child) => {
      deleteChild(returnFiber, child);
    });
  }
}

function placeChild(newFiber, lastPlacedIndex, newIndex, shouldTrackSideEffects) {
  // 更新 fiber 对象上面的 index
  // fiber 对象上面的 index 记录当前 fiber 节点在当前层级下的位置
  newFiber.index = newIndex;
  if (!shouldTrackSideEffects) {
    // 进入此 if，说明当前是初次渲染
    // 那么我们就不需要记录节点位置了
    return lastPlacedIndex;
  }
}
